#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include "rbtree.h"

#include "tkevent.h"
#include "tklog.h"
#include "constants.h"
#include "netutils.h"

struct custom_event 
{
	struct custom_event *next;

	void* data; /* point to custom_socket */

        struct rb_node node;
	unsigned long timeout_time;
	
	/* kinds of flag */
        unsigned accept_ready:1;
        unsigned write_ready:1;
        unsigned read_ready:1;
        unsigned active:1;      	/* register in event pool, active will be 1, and or not */
	unsigned active_read:1;
	unsigned active_write:1;
        unsigned timeout:1;     	/* if the event is timeout set 1 */
        unsigned in_timer_set:1;        /* if the event is set in timer, in_timer_set flag will be 1 */
        unsigned force_delay_read:1;    /* when both side have read event, the first will force the another delete event, 
						after read and send completly add the other's read event */
        unsigned shutdown:1;            /* aready close status, now wait for connection's other side's read or write */
        unsigned error:1;
};

#define CUSTOM_SOCKET_TYPE_DEFAULT	0
#define CUSTOM_SOCKET_TYPE_LISTEN	1

static int hd_epoll_listen_accept(struct epoll_env *env, struct custom_socket *s, void *pv, int event_type);

void set_epoll_after_accept(struct epoll_env *env, after_accept_entry after_accept)
{
	env->after_accept = after_accept;
}

void set_epoll_after_connect(struct epoll_env *env, after_connect_entry after_connect)
{
	env->after_connect = after_connect;
}

struct custom_event* get_custom_event(void *data)
{
	struct custom_event *event = malloc(sizeof(struct custom_event));
	memset(event, 0x00, sizeof(struct custom_event));
	
	event->data = data;

	return event;
}

struct custom_socket* get_custom_socket()
{
	struct custom_socket* s = (struct custom_socket*)malloc(sizeof(struct custom_socket));
	if (!s)
		return NULL;

	memset(s, 0x00, sizeof(struct custom_socket));
	s->event = get_custom_event(s);
	if (!s->event) {
		free(s);
		return NULL;
	}
	s->type = CUSTOM_SOCKET_TYPE_DEFAULT;

	return s;	
}

struct custom_socket* get_custom_listen_socket()
{
	struct custom_socket *s = NULL;

	if ((s = get_custom_socket()) == NULL)
		return NULL;
	
	s->type = CUSTOM_SOCKET_TYPE_LISTEN;

	return s;
}

/*
ip == NULL: listen ANY 
*/
int init_custom_listen_socket(struct custom_socket *s, char *ip, int port)
{
	struct sockaddr_in addr;
	int listen_fd;

        memset(&addr, 0x00, sizeof(struct sockaddr_in));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
	if (ip == NULL) {
		addr.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	else {
		if (inet_pton(addr.sin_family, ip, &addr.sin_addr.s_addr) <= 0) {
			elog("inet_pton ip[%s] failed-error[%d]", ip, errno);
			return -1;
		}
	}
		
        if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
                elog("socket failed-error[%d]", errno);
                return -2;
        }

        set_nonblocking(listen_fd);
        set_reuseaddr(listen_fd, 1);

        if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
		elog("bind failed, error[%d]", errno);
                close(listen_fd);
                return -3;
        }

        if (listen(listen_fd, 1024) == -1) {
		elog("listen failed, error[%d]", errno);
                close(listen_fd);
                return -4;
        }

	memcpy(&s->addr.sockaddr, &addr, sizeof(struct sockaddr_in));
	if (ip == NULL) {
		strcpy(s->addr.ipv4, "");
	}
	else {
		strcpy(s->addr.ipv4, ip);
	}
	s->addr.port = port;
	s->sockfd = listen_fd;
	s->handler =  hd_epoll_listen_accept;
	s->conn_ptr = NULL;
	s->merrno = 0;
	s->finished = 0;
	s->failed = 0;
	
	return 0;
}

void destory_custom_socket(struct epoll_env *env, struct custom_socket *s)
{
	if (s == NULL)
		return;

	struct custom_event *event = (struct custom_event*)s;

	if (s->sockfd > 0) {
		epoll_del_rw_event(env, event);
		close(s->sockfd);
	}
		
	if (s->event) {
		free(s->event);
		s->event = NULL;
	}
	if (s)
		free(s);
}

int is_accept(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
	return event->accept_ready;
} 

int is_writable(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return event->write_ready;	
}

int is_readable(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
        return event->read_ready;
}

int is_active(void *pv) 
{
	struct custom_event* event = (struct custom_event*)pv;
        return event->active;
}

int is_active_read(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
        return event->active_read;
}

int is_active_write(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return event->active_write;
}

int is_timeout(void *pv) 
{
	struct custom_event* event = (struct custom_event*)pv;
        return event->timeout;
}

int is_in_timer_set(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
        return event->in_timer_set;
}

int is_force_delay_read(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
	return event->force_delay_read;
}

int is_shutdown(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return event->shutdown;
}

int is_error(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return event->error;
}

void set_accept(void *pv,int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
	event->accept_ready = flag;
} 

void set_writable(void *pv,int flag)
{
        struct custom_event* event = (struct custom_event*)pv;
        event->write_ready = flag;	
}

void set_readable(void *pv,int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
        event->read_ready = flag;
}

void set_active(void *pv,int flag) 
{
	struct custom_event* event = (struct custom_event*)pv;
        event->active = flag;
}

void set_active_read(void *pv,int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
        event->active_read = flag;
}

void set_active_write(void *pv,int flag)
{
        struct custom_event* event = (struct custom_event*)pv;
        event->active_write = flag;
}

void set_timeout(void *pv,int flag) 
{
	struct custom_event* event = (struct custom_event*)pv;
        event->timeout = flag;
}

void set_in_timer_set(void *pv,int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
        event->in_timer_set = flag;
}

void set_force_delay_read(void *pv,int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
	event->force_delay_read = flag;
}

void set_shutdown(void *pv,int flag)
{
        struct custom_event* event = (struct custom_event*)pv;
        event->shutdown = flag;
}

void set_error(void *pv,int flag)
{
        struct custom_event* event = (struct custom_event*)pv;
        event->error = flag;
}

void set_event_data(void *pv, void *data)
{
        struct custom_event* event = (struct custom_event*)pv;
	event->data = data;
}
void* get_event_data(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
	return event->data;
}

struct epoll_env* create_epoll_env(after_accept_entry after_accept, after_connect_entry after_connect)
{
	int len = 0;
	int epollfd;
	struct epoll_env *env = NULL;

	env = (struct epoll_env*)malloc(sizeof(struct epoll_env));
	if (!env)
		return NULL;

	env->epollfd = epoll_create(1024);
	
	if (env->epollfd == -1) {
                elog("epoll create failed[%d]-errno[%d]", env->epollfd, errno);
		free(env);	
                return NULL;
	}

        len = EPOLL_MAX_WAITEVENTS_NUM * sizeof(struct epoll_event);
        env->epoll_wait_events = (struct epoll_event*)malloc(len);

        if (env->epoll_wait_events == NULL) {
		free(env);	
                return NULL;
        }
        memset(env->epoll_wait_events, 0x00, len);

	env->after_accept = after_accept;
	env->after_connect = after_connect;

        return env;
	
}

int destory_epoll_env(struct epoll_env *env)
{
	if (env == NULL)
		return 0;

	if (close(env->epollfd) == -1) 
		return -1;
	
	free(env->epoll_wait_events);	
	free(env);
	
	return 0;
}

/*
event-> custom_event
*/
static int epoll_add_event(struct epoll_env *env, void *event, int event_type)
{
	struct epoll_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket 	*s = NULL;
	unsigned int events = 0;
	int op = 0;
	int needadd = 0;
	unsigned int org_event = 0;

	ev = (struct custom_event*)event;
	s = (struct custom_socket*)ev->data;

	if (ev->active_write && ev->active_read) {
		return 0;
	}

	if (	!ev->active 					||
		((event_type & EPOLLIN) && !ev->active_read) 	||
		((event_type & EPOLLOUT) && !ev->active_write)
	) 
	{
		needadd = 1;
	}

	if (!needadd)
		return 0;

	events = event_type;

	op = EPOLL_CTL_ADD;
	if (ev->active) {
		op = EPOLL_CTL_MOD;
	}

	if (ev->active_read) {
		org_event = org_event | EPOLLIN;
	}
	if (ev->active_write) {
		org_event = org_event | EPOLLOUT;
	}

	if (event_type & EPOLLIN) {
		if (ev->active_read) {
			events = (events & (~EPOLLIN));		
		}
	}	
	if (event_type & EPOLLOUT) {
		if (ev->active_write) {
			events = (events & (~EPOLLOUT));		
		}
	}

	memset(&ee, 0x00, sizeof(ee));
//	ee.events = (org_event | events | EPOLLET | EPOLLRDHUP);
	ee.events = (org_event | events | EPOLLET);
	ee.data.ptr = s;

	dlog("events[%d] - ee.events[%u] - epolleockfd[%d]", events,  ee.events, env->epollfd);
	if (epoll_ctl(env->epollfd, op, s->sockfd, &ee) == -1) {
		elog("epoll ctl failed,op[%d]-events[%d]-errno[%d]", op, ee.events, errno); 
                return -1;
        }

	ev->active = 1;
	if (events & EPOLLIN)
		ev->active_read = 1;
	if (events & EPOLLOUT) 
		ev->active_write = 1;
	
	return 0;
}

int epoll_del_event(struct epoll_env *env, void *event, int event_type)
{
	struct epoll_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket	*s = NULL;
	unsigned int events = 0;
	unsigned int org_event = 0;
	int op = 0;

	ev = (struct custom_event*)event;
	s = ev->data;
	if (ev->active == 0) {
		return 0;
	}

	if (ev->active_read && (event_type & EPOLLIN))	
		events |= EPOLLIN;
	if (ev->active_write && (event_type & EPOLLOUT)) 
		events |= EPOLLOUT;

	if (!events)
		return 0;

	op = EPOLL_CTL_DEL;
	if ( 	(
			events == EPOLLIN 
			&& 
			ev->active_write
		) 
		||
		(	events == EPOLLOUT 
			&& 
			ev->active_read
		) 
	)
	{
		op = EPOLL_CTL_MOD;
	}	

        if (ev->active_read) {
                org_event = org_event | EPOLLIN;
        }
        if (ev->active_write) {
                org_event = org_event | EPOLLOUT;
        }

	memset(&ee, 0x00, sizeof(struct epoll_event));
	ee.events = (org_event & ~events) | EPOLLET;

	ee.data.ptr = s;
        if (epoll_ctl(env->epollfd, op, s->sockfd, &ee) == -1) {
		elog("epoll ctl failed,op[%d]-events[%d]-errno[%d]", op, ee.events, errno); 
                return -1;
        }
	
	if (events & EPOLLIN)
		ev->active_read = 0;
	if (events & EPOLLOUT)
		ev->active_write = 0;

	if (ev->active_read == 0 && ev->active_write == 0)  {
		ev->active = 0;
	}
	else {
		ev->active = 1;
	}

	return 0;
}

int epoll_set_event(struct epoll_env *env, void *event, int event_type)
{
	struct epoll_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket	*s = NULL;
	int op = 0;

	ev = (struct custom_event*)event;
	s = ev->data;
	
	if (!event_type)
		return 0;

	op = EPOLL_CTL_MOD;
	if (!ev->active) {
		op = EPOLL_CTL_ADD;
	}

	ee.events = event_type | EPOLLET;
	ee.data.ptr = s;

        if (epoll_ctl(env->epollfd, op, s->sockfd, &ee) == -1) {
		elog("epoll ctl failed, op[%d]-events[%d]-errno[%d]", op, ee.events, errno); 
                return -1;
        }
	
	ev->active_read = 0;
	ev->active_write = 0;

	if (ee.events & EPOLLIN)
		ev->active_read = 1;
	if (ee.events & EPOLLOUT)
		ev->active_write = 1;

	ev->active = 1;

	return 0;
}

int epoll_del_fd(struct epoll_env *env, void *event)
{
	struct epoll_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket	*s = NULL;

	ev = (struct custom_event*)event;
	s = ev->data;
	
	if (!ev->active) {
		return 0;
	}

        if (epoll_ctl(env->epollfd, EPOLL_CTL_DEL, s->sockfd, &ee) == -1) {
		elog("epoll ctl failed, op[%d]-events[%d]-errno[%d]", EPOLL_CTL_DEL, ee.events, errno); 
                return -1;
        }
	
	ev->active = 0;

	return 0;
	
}

int epoll_add_listen_event(struct epoll_env *env, void *event)
{
	return epoll_add_event(env, event, EPOLLIN);
}

int epoll_del_listen_event(struct epoll_env *env, void *event)
{
	return epoll_del_event(env, event, EPOLLOUT);
}

int epoll_add_read_event(struct epoll_env *env, void *event)
{
	return epoll_add_event(env, event, EPOLLIN);
}

int epoll_add_write_event(struct epoll_env *env, void *event)
{
	return epoll_add_event(env, event, EPOLLOUT);
}

int epoll_del_read_event(struct epoll_env *env, void *event)
{
	return epoll_del_event(env, event, EPOLLIN);
}

int epoll_del_write_event(struct epoll_env *env, void *event)
{
	return epoll_del_event(env, event, EPOLLOUT);
}

int epoll_del_rw_event(struct epoll_env *env, void *event)
{
	return epoll_del_event(env, event, EPOLLIN | EPOLLOUT);
}

int epoll_add_rw_event(struct epoll_env *env, void *event)
{
	return epoll_add_event(env, event, EPOLLIN | EPOLLOUT);
}

void set_custom_socket_pv(struct custom_socket *s, void *pv)
{
	s->pv = pv;	
}
void* get_custom_socket_pv(struct custom_socket *s)
{
	return s->pv;
}

static int hd_epoll_listen_accept(struct epoll_env *env, struct custom_socket *s, void *pv, int event_type) 
{
	int r = 0;
	int new_sockfd;
	int new_addrlen;
	struct sockaddr_in new_addr;
	struct custom_socket *new_s = NULL;

	while (1) {
		new_addrlen = sizeof(struct sockaddr_in);
		dlog("addrlen[%d]\n", new_addrlen);
		new_sockfd = accept(s->sockfd, (struct sockaddr*)&new_addr, &new_addrlen);
                if (new_sockfd == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                dlog("accept EAGAIN");
                        }
                        else if (errno == EMFILE || errno == ENFILE) {
                                /* need wait for a moment */
                                /* delay accept */
                                dlog("too many fd, access the system limit");
                        }
                        else {
                                elog("listen ip[%s]-port[%d]-listen_fd[%d] accept failed, errno[%d]", s->addr.ipv4, s->addr.port, s->sockfd, errno);
                        }
                        break;
                }
		
		if ((new_s = get_custom_socket()) == NULL) {
			close(new_sockfd);
			elog("not enough memory, force close new sockfd");
			break;
		}

		new_s->sockfd = new_sockfd;

		/* set tcp opt */
		set_nonblocking(new_sockfd);
		set_reuseaddr(new_sockfd, 1);
		set_tcpkeepalive(new_sockfd);

		/* set address */
		memcpy(&new_s->addr.sockaddr, &new_addr, new_addrlen); 
		strcpy(new_s->addr.ipv4, inet_ntoa(new_addr.sin_addr));
		new_s->addr.port = ntohs(new_addr.sin_port);
		
		if (env->after_accept(env, new_s, pv)) {
			elog("after accept custom handler failed");	
		} 
		ilog("[NEW client] connect,ip[%s]-port[%d]", new_s->addr.ipv4, new_s->addr.port);
	}

	return 0;
}

int epoll_process_events(struct epoll_env* env, int timeout)
{
	int r;
	int i;
	int events_num = 0;
	struct custom_socket *s = NULL;
	struct custom_event *ev = NULL;
	int events;
	void *pv = NULL;

	memset(env->epoll_wait_events, 0x00, sizeof(EPOLL_MAX_WAITEVENTS_NUM * sizeof(struct epoll_event)));
	events_num = epoll_wait(env->epollfd, env->epoll_wait_events, EPOLL_MAX_WAITEVENTS_NUM, timeout);
	r = (events_num == -1) ? errno : 0;
        if (r) {
                if (r == EINTR) {
			elog("epoll wait eintr");
                        return 0;
		}
                else {
			elog("epoll wait failed, errno[%d]", errno);
                        return -1;
		}
        }

	if (events_num == 0) {
		return 0;
	}

	for (i = 0; i < events_num; i++) {
                s = env->epoll_wait_events[i].data.ptr;
                events = env->epoll_wait_events[i].events;
		ev = s->event;
		pv = s->pv;

		ilog("EVENT[EPOLLIN:%d EPOLLOUT:%d EPOLLERR:%d EPOLLHUP:%d] listen(ip[%s]-port[%d]-sockedfd[%d]-event[%d])", 
										EPOLLIN, EPOLLOUT, EPOLLERR, EPOLLHUP,
										s->addr.ipv4, s->addr.port, s->sockfd, events);
		if (s->finished || s->failed) {
			if (s->finished) 
				ilog("had finished");
			if (s->failed)
				ilog("had failed");
			continue;
		}
		
                if (events & (EPOLLERR | EPOLLHUP)) {
			/* local error */
			if (s->type == CUSTOM_SOCKET_TYPE_LISTEN) {
                                if (!s->handler) 
                                        ilog("listen ip[%s]-port[%d] event's handler is null", s->addr.ipv4, s->addr.port);
                                else
                                        s->handler(env, s, pv, EVENT_LOCAL_ERROR);
                        }
                        else {
                                if (!s->handler) 
                                        ilog("ip[%s]-port[%d] event's handler is null", s->addr.ipv4, s->addr.port);
                                else
                                        s->handler(env, s, pv, EVENT_LOCAL_ERROR);
                        } 
			ev->error = 1;
                }
/****
 * 		low epoll api has not EPOLLRDHUP
		else if (events & EPOLLRDHUP) {
			if (s->type == CUSTOM_SOCKET_TYPE_LISTEN) {
				ilog("listen never recive close message, not possible");
				return -1;
			}
			else {
                                if (!s->handler) 
                                        ilog("ip[%s]-port[%d] event's handler is null", s->addr.ipv4, s->addr.port);
				else 
					s->handler(env, s, pv, EVENT_REMOTE_CLOSE);
			}
		}
***/

		if (events & EPOLLIN) {
			if (!s->handler) {
				if (s->type == CUSTOM_SOCKET_TYPE_LISTEN) {
					flog("listen ip[%s]-port[%d] handler is null", s->addr.ipv4, s->addr.port);
				}
				else {
					flog("socket ip[%s]-port[%d] read handler is null", s->addr.ipv4, s->addr.port);
				}
			}
			else {
dlog("EVENT(ip[%s]-port[%d]-sockedfd[%d]-event[%d])", s->addr.ipv4, s->addr.port, s->sockfd, events);
                                s->handler(env, s, pv, EVENT_READ);
                        }
                }      
                if (events & EPOLLOUT) {
			if (!s->handler) {
				flog("socket ip[%s]-port[%d] write handler is null", s->addr.ipv4, s->addr.port);
			}

			s->handler(env, s, pv, EVENT_WRITE);
                }
	}

	return events_num;
}

